import QtQuick 1.1
import QtMultimediaKit 1.1
import QtMobility.sensors 1.1
import CameraFeatures 1.0

Rectangle {
    id: main

    property int counterCalled: 0 // how many times capture has been called
    property int counterSaved: 0 // how many pictures have been saved
    property bool sensorEnable: true

    // The resolution to capture the image at. If empty, the system will pick a good size.
    property string resolution: "3248x2448" // N9 4:3 8M
    property variant resolutionList: [] // resolutions supported by current device

    property int captureInterval: 300 // ms
    property variant imageList: [] // paths of saved images during the session

    width: 480
    height: 854
    color: "slategrey"
    focus: true

    Keys.onPressed: {
        console.log("onPressed")
    }

    Keys.onVolumeDownPressed: {
        // decrease resolution or something else
        console.log("onVolumeDownPressed")
    }
    Keys.onVolumeUpPressed: {
        // increase resolution ...
        console.log("onVolumeUpPressed")
    }

    Camera {
        id: camera
        anchors.fill: parent
        flashMode: Camera.FlashOff
        exposureMode: Camera.ExposureSports
        whiteBalanceMode: Camera.WhiteBalanceAuto
        captureResolution: main.resolution
        onImageCaptured: {
            // preview
            console.log("onImageCaptured. preview: " + preview)
        }
        onImageSaved: {
            // path
            console.log("onImageSaved. path: " + path)
            var list = imageList;
            list.push(path);
            imageList = list;
            main.counterSaved++;
        }
        onCaptureFailed: {
            // message
            console.log("onCaptureFailed. message: " + message)
        }
        onError: {
            // error, errorString
            console.log("onError. error: " + error + ", errorString: " + errorString)
        }
    }

    CameraFeatures {
        id: cameraFeat
        property int cameraDevice: 0

        function getFeatures() {
            var devices = getAvailableDevices(); // string list
            console.log("getFeatures. devices: " + devices); // primary,secondary
            startGetFeatures(devices[cameraDevice]);
        }

        Component.onCompleted: {
            console.log("CameraFeatures. Component.onCompleted")
            getFeatures();
        }
        onCameraDeviceChanged: {
            console.log("CameraFeatures.onCameraDeviceChanged")
            getFeatures()
        }

        onFeaturesRetrieved: {
            console.log("CameraFeatures.onFeaturesRetrieved")
            var list = cameraFeat.getSupportedResolutionsList();
            console.log("getSupportedResolutionsList: " + list)
            if (list) {
               main.resolutionList = list;
            }
            camera.start()
        }
    }

    //
    // New sensor types and classes for gyroscope and light sensors are made
    // available in API for future use. At the moment there is no devices having these sensors however.

    Accelerometer {
        id: motionSensor

        property int historyCount: 4 // how many values are stored for prev calculation
        property real threshold: 0.2 // diff between each previous value
        property variant previousX: [] // list of n previous values
        property variant previousY: [] // list of n previous values
        property variant previousZ: [] // list of n previous values
        property bool stableX: false // x values are within threshold
        property bool stableY: false // x values are within threshold
        property bool stableZ: false // x values are within threshold
        property variant almost: [0, 0, 0] // how close to stable 0..1
        property bool capture: stableX && stableY && stableZ

        function checkThreshold(reading) {
            previousX = checkHistoryLength(previousX, reading.x);
            stableX = checkThresholdAxis(previousX, 0);

            previousY = checkHistoryLength(previousY, reading.y);
            stableY = checkThresholdAxis(previousY, 1);

            previousZ = checkHistoryLength(previousZ, reading.z);
            stableZ = checkThresholdAxis(previousZ, 2);
        }

        // list = one of previousXYZ
        // r = reading.xyz
        function checkHistoryLength(list, r) {
            list.push(r);
            if (list.length > historyCount) {
                list.splice(0, 1);
            }
            return list;
        }

        // list = previous[X,Y,Z]
        function checkThresholdAxis(list, almostIndex) {
            var len = list.length;
            if (len > 1) {
                var total = 0;
                var step = 1 / len;
                var prev = list[0]; // initial
                var curr;
                for(var i = 1; i < len; ++i) {
                    curr = list[i];
                    if (Math.abs(curr - prev) > motionSensor.threshold) {
                        return false;
                    }
                    prev = curr;
                    total += step;

                    // Need to write this every time to keep it up to date
                    var almost = motionSensor.almost;
                    almost[almostIndex] = total;
                    motionSensor.almost = almost;
                }

                return true;
            }
            return false;
        }

        active: main.sensorEnable
        onReadingChanged: {
            if (reading) {
                checkThreshold(reading);
                var list = [
                            "x: " + reading.x,
                            "y: " + reading.y,
                            "z: " + reading.z,
                            "busy: " + motionSensor.busy,
                            "resolution: " + main.resolution,
                            "captureResolution: " + camera.captureResolution.width + "x" + camera.captureResolution.height,
                            "aperture: " + camera.aperture,
                            "exposureMode: " + camera.exposureMode,
                            "shutterSpeed: " + camera.shutterSpeed,
                            "exposureCompensation: " + camera.exposureCompensation,
                            "Called: " + main.counterCalled,
                            "Saved: " + main.counterSaved
                        ];
                infoText.text = list.join("\n");
            }
        }

        /*
        The reading contains 3 values, measured in degrees per second that define the movement of
        the device around the x, y and z axes. Unlike QRotationReading, the values represent the current
        angular velocity rather than a fixed rotation. The measurements are in degrees per second.
        */
    }

    Item {
        id: infoBox
        width: main.width / 6
        anchors.left: parent.left
        anchors.top: parent.top
        anchors.bottom: parent.bottom

        Rectangle {
            anchors.fill: parent
            color: "black"
            opacity: 0.4
        }

        Text {
            id: infoText
            anchors.margins: 4
            wrapMode: Text.WordWrap
            color: "snow"
            font.pixelSize: 16
        }

        Column {
            anchors.bottom: parent.bottom
            spacing: 4
            Repeater {
                model: motionSensor.almost

                Rectangle {
                    height: 10
                    width: infoBox.width
                    color: "pink"
                    Rectangle {
                        color: "lightgreen"
                        height: parent.height
                        width: parent.width * modelData
                    }
                }
            }

        }
    }
    Flickable {
        id: resoList
        width: main.width / 6
        anchors.left: infoBox.right
        anchors.top: parent.top
        anchors.bottom: parent.bottom
        contentHeight: resoColumn.height

        Column {
            id: resoColumn
            spacing: 10

            Repeater {
                model: main.resolutionList
                Rectangle {
                    width: resoList.width
                    height: 24
                    color: "slateblue"
                    Text {
                        anchors.centerIn: parent
                        text: modelData.width + "x" + modelData.height
                        color: "snow"
                        font.pixelSize: 16
                    }
                }
            }
        }

    }

    Timer {
        id: intervalTimer
        interval: main.captureInterval
        repeat: true
        triggeredOnStart: true
        running: pressArea.pressed || motionSensor.capture
        onTriggered: {
            //console.log("onTriggered. camera.lockStatus: " + camera.lockStatus)
            camera.captureImage();
            main.counterCalled++;
        }
    }

    // While mouse is pressed, images are taken
    MouseArea {
        id: pressArea
        anchors.fill: parent
        onPressAndHold: {
            console.log("onPressAndHold")
        }
        onPressed: {
            console.log("onPressed")
        }
        onReleased: {
            console.log("onReleased")
        }
        onCanceled: {
            console.log("onCanceled")
        }
        onDoubleClicked: {
            console.log("onDoubleClicked")
        }
        onPressedChanged: {
            console.log("onPressedChanged. pressed: " + pressed)
        }

        Rectangle {
            id: pressBox
            anchors.fill: parent
            color: "pink"
            opacity: 0.3
            visible: parent.pressed
        }
    }


    PinchArea {
        id: pinchArea

        property int resW: 0
        property int resH: 0
        property string resolution: ""
        property bool pinching: false

        visible: false
        anchors.fill: parent

        onPinchFinished: {
            console.log("onPinchFinished. scale: " + pinch.scale + ", angle: " + pinch.angle)

            main.resolution = pinchArea.resolution
            pinching = false;
        }
        onPinchStarted: {
            console.log("onPinchStarted. scale: " + pinch.scale + ", angle: " + pinch.angle)

            var list = main.resolution.split("x");
            resW = parseInt(list[0]);
            resH = parseInt(list[1]);
            pinching = true;
        }
        onPinchUpdated: {
            //console.log("onPinchUpdated. scale: " + pinch.scale + ", angle: " + pinch.angle)

            var rad = pinch.angle * Math.PI / 180
            var scaleW = Math.abs(Math.cos(rad) * pinch.scale);
            var scaleH = Math.abs(Math.sin(rad) * pinch.scale);

            // Prevent stucking to 0x0 by adding some pixels
            pinchArea.resolution = Math.round(resW * scaleW + 10) + "x" +  Math.round(resH * scaleH + 10)
        }

        Item {
            anchors.fill: parent
            visible: pinchArea.pinching

            Rectangle {
                anchors.fill: parent
                color: "violet"
                opacity: 0.5
            }

            Column {
                anchors.centerIn: parent

                Text {
                    text: "Use Pinch to change the desired resolution."
                    font.pointSize: 20
                    horizontalAlignment: Text.AlignHCenter
                }
                Text {
                    text: pinchArea.resolution
                    font.pointSize: 20
                    horizontalAlignment: Text.AlignHCenter
                }
            }
        }

    }

    ListView {
        id: previewList

        anchors {
            top: main.top
            bottom: main.bottom
            right: main.right
        }

        clip: true
        contentHeight: childrenRect.height
        model: main.imageList
        width: main.width / 6

        delegate: Component {
            Image {
                width: previewList.width
                height: width / 2
                fillMode: Image.PreserveAspectCrop
                sourceSize.width: width
                sourceSize.height: height
                source: modelData
                Text {
                    anchors.centerIn: parent
                    text: modelData
                    wrapMode: Text.WrapAnywhere
                }
            }
        }

        /*
        onAdd: {
            positionViewAtEnd();
        }*/
    }

}
